package jp.co.systemi.asp.workflow.apply;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

import jp.co.systemi.asp.utils.ConfirmDialog;
import jp.co.systemi.asp.utils.DModalWindow;
import jp.co.systemi.asp.workflow.ICallback;
import jp.co.systemi.asp.workflow.Main;
import jp.co.systemi.asp.workflow.annotation.FormInput;
import jp.co.systemi.asp.workflow.approve.ApproverList;
import jp.co.systemi.asp.workflow.data.Apply;
import jp.co.systemi.asp.workflow.data.ApplyMeta;
import jp.co.systemi.asp.workflow.data.Common;
import jp.co.systemi.asp.workflow.data.User;
import jp.co.systemi.asp.workflow.data.UserMeta;
import jp.co.systemi.asp.workflow.mail.Mail;
import jp.co.systemi.asp.workflow.peer.ApplyPeer;
import jp.co.systemi.asp.workflow.peer.UserPeer;

import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
import org.slim3.datastore.Datastore;
import org.slim3.datastore.GlobalTransaction;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class ApplyRef extends Main implements ICallback {
    /**
     * ログ出力 クラス名をあわせること
     */
    private static final Logger log = Logger
            .getLogger(ApplyRef.class.getName());
    Boolean incApproved = false;
    List<Apply> applys = new ArrayList<Apply>(); // 申請分、却下分

    List<Apply> approvers = new ArrayList<Apply>(); // 承認者および承認状況
    // 承認者一覧モデルウィンドウ
    final DModalWindow approverListDialog = new DModalWindow(
            "wi_approverListDialog");
    IApplyInfoPanel applyInfoPanel = null;

    // 承認が進んでいる場合の確認モデルウィンドウ
    final DModalWindow confirmCancel = new DModalWindow("wi_confirmCancel");
    /**
     * FormInput Annotationがあれば、自動的にMainFormにaddされる、ただし、publicにする必要
     */
    @FormInput
    public AjaxButton wi_btnCancel = new AjaxButton("wi_btnCancel") {
        private static final long serialVersionUID = 1L;

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
            doCancel(target, form, false);
        }

    };

    private void doCancel(AjaxRequestTarget target, Form<?> form,
            boolean confirmed) {
        UserService userService = UserServiceFactory.getUserService();

        com.google.appengine.api.users.User usr = userService.getCurrentUser();
        String loginId = usr.getEmail();

        Key applyNo = applyInfoPanel.getApplyNo();
        log.info("applyNo: " + applyNo);
        ApplyMeta am = ApplyMeta.get();
        List<Apply> applies = Datastore.query(am).filter(
                am.summaryId.equal(applyNo)).sort(am.seq.asc).asList();
        int i = 0;
        for (Apply apply : applies) {
            i++;
            if (apply.getStatus().equals(Common.APPLY_STATUS.APPROVED)) {
                if (!confirmed) {
                    // 確認ダイアログを表示する
                    confirmCancel.setInitialHeight(150);
                    confirmCancel.setInitialWidth(250);
                    confirmCancel.show(target);
                    return;
                }
            } else {
                break;
            }
        }
        GlobalTransaction gtx = Datastore.beginGlobalTransaction();
        // 申請内容を取消する
        applyInfoPanel.setCancelled(gtx);
        // 決裁レコードを更新
        Apply summary = Datastore.query(am).filter(am.id.equal(applyNo))
                .asSingle();
        if (summary == null) {
            error(getString("data.error"));
            target.addComponent(feedback);
            return;
        }
        summary.setStatus(Common.APPLY_STATUS.CANCELED);
        gtx.put(summary);
        for (Apply apply : applies) {
            apply.setStatus(Common.APPLY_STATUS.CANCELED);
            gtx.put(apply);
        }
        gtx.commit();

        // メール送信
        UserMeta um = UserMeta.get();
        User me = Datastore.query(um).filter(um.loginId.equal(usr.getEmail()))
                .asSingle();
        if (me == null) {
            error(getString("data.error"));
            target.addComponent(feedback);
            return;
        }

        WebRequest wr = (WebRequest) getRequestCycle().getRequest();
        HttpServletRequest sr = wr.getHttpServletRequest();
        String domain = sr.getServerName();
        String requestUrl = Main
                .getRequestUrl(((ServletWebRequest) getRequest())
                        .getHttpServletRequest());

        // 第一未承認者へ送信
        Mail mail = new Mail(this.getClass().getPackage().getName().replace(
                ".", "/")
                + "/ApplyRef.cancel.to.approver.vm");
        // Fromを設定
        mail.setFrom(usr.getEmail(), UserPeer.getName(me));
        mail.addTo(applies.get(i - 1).getApprover(), applies.get(i - 1)
                .getApproverName());
        // 件名
        mail.setSubject(getString("apply.cancel.mail.subject"));

        // URL設定
        String approveURL = requestUrl + "/approve/ApproveRef";
        approveURL = userService.createLoginURL(approveURL, domain);
        mail.put("category", summary.getCategory());
        mail.put("url", approveURL);
        mail.send();

        // データを取り直し
        applys.clear();
        // 申請分、または却下分
        List<Apply> applyData = ApplyPeer.getApplySummaries(loginId,
                incApproved);
        if (applyData == null) {
            error(getString("data.error"));
            return;
        }
        applys.addAll(applyData);
        ((Panel) applyInfoPanel).setVisible(false);
        wi_btnCancel.setVisible(false);
        wi_btnApply.setVisible(false);
        wi_btnAccept.setVisible(false);
        target.addComponent(form);
    }

    /**
     * FormInput Annotationがあれば、自動的にMainFormにaddされる、ただし、publicにする必要
     */
    @FormInput
    public AjaxButton wi_btnApply = new AjaxButton("wi_btnApply") {
        private static final long serialVersionUID = 1L;

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
            // 編集モードの戻す
            Key applyNo = applyInfoPanel.getApplyNo();
            log.info("applyNo: " + applyNo);
            ApplyMeta am = ApplyMeta.get();
            Apply applySummary = Datastore.query(am).filter(
                    am.id.equal(applyNo)).asSingle();
            if (applySummary == null) {
                error(getString("data.error"));
                target.addComponent(feedback);
                return;
            }
            if (!applySummary.getStatus().equals(Common.APPLY_STATUS.REJECTED)) {
                error(getString("data.error"));
                target.addComponent(feedback);
                return;
            }
            GlobalTransaction gtx = Datastore.beginGlobalTransaction();
            // まず受入して
            applySummary.setStatus(Common.APPLY_STATUS.ACCEPTED);
            // Datastore.put(applySummary);
            gtx.put(applySummary);
            // 　編集モードの設定
            applyInfoPanel.setEditing(gtx);
            gtx.commit();

            UserService userService = UserServiceFactory.getUserService();

            com.google.appengine.api.users.User usr = userService
                    .getCurrentUser();
//            String loginId = usr.getEmail();

            List<Apply> applies = Datastore.query(am).filter(
                    am.summaryId.equal(applyNo)).sort(am.seq.asc).asList();
            int i = 0;
            for (Apply apply : applies) {
                i++;
                if (apply.getStatus().equals(Common.APPLY_STATUS.REJECTED)) {
                    break;
                }
            }
            // メール送信
            UserMeta um = UserMeta.get();
            User me = Datastore.query(um).filter(
                    um.loginId.equal(usr.getEmail())).asSingle();
            if (me == null) {
                error(getString("data.error"));
                target.addComponent(feedback);
                return;
            }

            WebRequest wr = (WebRequest) getRequestCycle().getRequest();
            HttpServletRequest sr = wr.getHttpServletRequest();
            String domain = sr.getServerName();
            String requestUrl = Main
                    .getRequestUrl(((ServletWebRequest) getRequest())
                            .getHttpServletRequest());

            // 却下した承認者へ送信
            Mail mail = new Mail(this.getClass().getPackage().getName()
                    .replace(".", "/")
                    + "/ApplyRef.reapply.to.approver.vm");
            // Fromを設定
            mail.setFrom(usr.getEmail(), UserPeer.getName(me));
            mail.addTo(applies.get(i - 1).getApprover(), applies.get(i - 1)
                    .getApproverName());
            // 件名
            mail.setSubject(getString("apply.accept.mail.subject"));

            // URL設定
            String approveURL = requestUrl + "/approve/ApproveRef";
            approveURL = userService.createLoginURL(approveURL, domain);
            mail.put("category", applySummary.getCategory());
            mail.put("url", approveURL);
            mail.send();

            setResponsePage(PaidHolidayApply.class);
        }

    };

    /**
     * FormInput Annotationがあれば、自動的にMainFormにaddされる、ただし、publicにする必要
     */
    @FormInput
    public AjaxButton wi_btnAccept = new AjaxButton("wi_btnAccept") {
        private static final long serialVersionUID = 1L;

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
            UserService userService = UserServiceFactory.getUserService();

            com.google.appengine.api.users.User usr = userService
                    .getCurrentUser();
            String loginId = usr.getEmail();
            Key applyNo = applyInfoPanel.getApplyNo();
            log.info("applyNo: " + applyNo);
            ApplyMeta am = ApplyMeta.get();
            Apply applySummary = Datastore.query(am).filter(
                    am.id.equal(applyNo)).asSingle();
            if (applySummary == null) {
                error(getString("data.error"));
                target.addComponent(feedback);
                return;
            }
            if (!applySummary.getStatus().equals(Common.APPLY_STATUS.REJECTED)) {
                error(getString("data.error"));
                target.addComponent(feedback);
                return;
            }
            GlobalTransaction gtx = Datastore.beginGlobalTransaction();
            applySummary.setStatus(Common.APPLY_STATUS.ACCEPTED);
            // Datastore.put(applySummary);
            gtx.put(applySummary);

            applyInfoPanel.setAccepted(gtx);
            gtx.commit();

            List<Apply> applies = Datastore.query(am).filter(
                    am.summaryId.equal(applyNo)).sort(am.seq.asc).asList();
            int i = 0;
            for (Apply apply : applies) {
                i++;
                if (apply.getStatus().equals(Common.APPLY_STATUS.REJECTED)) {
                    break;
                }
            }
            // メール送信
            UserMeta um = UserMeta.get();
            User me = Datastore.query(um).filter(
                    um.loginId.equal(usr.getEmail())).asSingle();
            if (me == null) {
                error(getString("data.error"));
                target.addComponent(feedback);
                return;
            }

            WebRequest wr = (WebRequest) getRequestCycle().getRequest();
            HttpServletRequest sr = wr.getHttpServletRequest();
            String domain = sr.getServerName();
            String requestUrl = Main
                    .getRequestUrl(((ServletWebRequest) getRequest())
                            .getHttpServletRequest());

            // 却下した承認者へ送信
            Mail mail = new Mail(this.getClass().getPackage().getName()
                    .replace(".", "/")
                    + "/ApplyRef.accept.to.approver.vm");
            // Fromを設定
            mail.setFrom(usr.getEmail(), UserPeer.getName(me));
            mail.addTo(applies.get(i - 1).getApprover(), applies.get(i - 1)
                    .getApproverName());
            // 件名
            mail.setSubject(getString("apply.accept.mail.subject"));

            // URL設定
            String approveURL = requestUrl + "/approve/ApproveRef";
            approveURL = userService.createLoginURL(approveURL, domain);
            mail.put("category", applySummary.getCategory());
            mail.put("url", approveURL);
            mail.send();

            // データを再取得
            applys.clear();
            // 申請分、または却下分
            List<Apply> applyData = ApplyPeer.getApplySummaries(loginId,
                    incApproved);
            if (applyData == null) {
                error(getString("data.error"));
                return;
            }
            applys.addAll(applyData);
            ((Panel) applyInfoPanel).setVisible(false);
            wi_btnCancel.setVisible(false);
            wi_btnApply.setVisible(false);
            wi_btnAccept.setVisible(false);
            target.addComponent(form);
        }

    };

    /**
     * コンストラクター 画面の生成、イベント処理の定義はすべて、この中で完結する
     */
    public ApplyRef() {
        init();
    }

    private void init() {
        // Formを生成する
        final Form<Apply> form = new MainForm<Apply>(this, "wi_refApplyForm");
        // データストアーから初期化する入力項目の生成は一番先に行う
        UserService userService = UserServiceFactory.getUserService();

        com.google.appengine.api.users.User usr = userService.getCurrentUser();
        String loginId = usr.getEmail();
        // 申請分、または却下分
        List<Apply> applyData = ApplyPeer.getApplySummaries(loginId,
                incApproved);
        if (applyData == null) {
            error(getString("data.error"));
            return;
        }
        applys.addAll(applyData);
        // 申請リスト
        final WebMarkupContainer tblApply = new WebMarkupContainer(
                "wi_tblApply");
        tblApply.setOutputMarkupId(true);
        form.add(tblApply);
        tblApply.add(new ListView<Apply>("wi_trApply", applys) {
            private static final long serialVersionUID = 4846361379394092695L;

            @Override
            protected void populateItem(ListItem<Apply> item) {
                final Apply apply = item.getModelObject();
                SimpleDateFormat sdf = new SimpleDateFormat(
                        getString("date.format"));
                AjaxLink<Object> tdLinkApply = new AjaxLink<Object>(
                        "wi_tdLink2Apply") {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget target) {
                        form.remove("wi_applyInfoPanel");
                        PageParameters pars = new PageParameters();
                        pars.add("loginId", apply.getApplyee());
                        pars.add("applyNo", Long
                                .toString(apply.getId().getId()));
                        log.info("PageParameters: " + pars);
                        applyInfoPanel = new PaidHolidayRefPanel(
                                "wi_applyInfoPanel", pars);
                        ((Panel) applyInfoPanel).setOutputMarkupId(true);
                        form.add((Panel) applyInfoPanel);
                        ((Panel) applyInfoPanel).setVisible(true);

                        wi_btnCancel.setVisible(apply.getStatus().equals(
                                Common.APPLY_STATUS.APPLYING));

                        wi_btnApply.setVisible(apply.getStatus().equals(
                                Common.APPLY_STATUS.REJECTED));
                        wi_btnAccept.setVisible(apply.getStatus().equals(
                                Common.APPLY_STATUS.REJECTED));

                        target.addComponent(form);
                    }
                };
                item.add(tdLinkApply);
                tdLinkApply.add(new Label("wi_tdSeq", new PropertyModel<Long>(
                        apply, "seq")));
                AjaxLink<Object> tdLink2Approvers = new AjaxLink<Object>(
                        "wi_tdLink2Appovers") {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget target) {
                        approvers.clear();

                        List<Apply> applies = ApplyPeer.getApplies(apply
                                .getId());
                        if (applies == null) {
                            error(getString("data.error"));
                            target.addComponent(feedback);
                            return;
                        }
                        approvers.addAll(applies);

                        approverListDialog.setInitialHeight(400);
                        approverListDialog.setWindowClosedCallback(null);
                        approverListDialog.show(target);
                    }

                };
                item.add(tdLink2Approvers);
                tdLink2Approvers.add(new Label("wi_tdApplyNo",
                        new PropertyModel<Long>(apply, "id.id")));
                item.add(new Label("wi_tdCategory", new PropertyModel<String>(
                        apply, "category")));
                item
                        .add(new Label("wi_tdDate", sdf.format(apply
                                .getRegDate())));
                item.add(new Label("wi_tdMemo", new PropertyModel<String>(
                        apply, "memo")));
                item.add(new Label("wi_tdStatus", new PropertyModel<String>(
                        apply, "status")));
            }
        });

        approverListDialog.setTitle(getString("approverlistdialog.title"));
        approverListDialog.setPageCreator(new ModalWindow.PageCreator() {
            private static final long serialVersionUID = -6364600063465337078L;

            public Page createPage() {
                return new ApproverList(ApplyRef.this, approverListDialog);
            }
        });

        approverListDialog
                .setOKActionCallback(new ModalWindow.WindowClosedCallback() {
                    private static final long serialVersionUID = -1012735996565367949L;

                    public void onClose(AjaxRequestTarget target) {
                        target.addComponent(feedback);
                    }
                });
        approverListDialog
                .setCancelActionCallback(new ModalWindow.WindowClosedCallback() {
                    private static final long serialVersionUID = -1012735996565367949L;

                    public void onClose(AjaxRequestTarget target) {
                        target.addComponent(feedback);
                    }
                });
        // 閉じるボタン（X）をクリックした時に呼ばれる
        approverListDialog
                .setCloseButtonCallback(new ModalWindow.CloseButtonCallback() {
                    private static final long serialVersionUID = -2205343604513004971L;

                    public boolean onCloseButtonClicked(AjaxRequestTarget target) {
                        return true;
                    }
                });
        main.add(approverListDialog);
        // 実行時に選択された申請内容を表示する
        form
                .add(new Label("wi_applyInfoPanel",
                        getString("applyinfopanel.alt")));
        wi_btnCancel.setVisible(false);
        wi_btnApply.setVisible(false);
        wi_btnAccept.setVisible(false);

        confirmCancel.setTitle(getString("confirmcancel.title"));
        confirmCancel.setPageCreator(new ModalWindow.PageCreator() {
            private static final long serialVersionUID = -6364600063465337078L;

            public Page createPage() {
                return new ConfirmDialog(ApplyRef.this, confirmCancel,
                        getString("confirmcancel.message"));
            }
        });
        confirmCancel
                .setOKActionCallback(new ModalWindow.WindowClosedCallback() {
                    private static final long serialVersionUID = -1012735996565367949L;

                    public void onClose(AjaxRequestTarget target) {
                        doCancel(target, form, true);
                    }
                });
        main.add(confirmCancel);

        final AjaxCheckBox incApporved = new AjaxCheckBox("wi_incApproved", new PropertyModel<Boolean>(
                this, "incApproved")) {
            private static final long serialVersionUID = -9067370975847143168L;

            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                log.info("selection changed: " + incApproved);
                UserService userService = UserServiceFactory.getUserService();

                com.google.appengine.api.users.User usr = userService
                        .getCurrentUser();
                String loginId = usr.getEmail();
                // データを取り直し
                applys.clear();
                // 申請分、または却下分
                List<Apply> applyData = ApplyPeer.getApplySummaries(loginId,
                        incApproved);
                if (applyData == null) {
                    error(getString("data.error"));
                    return;
                }
                applys.addAll(applyData);
                // ((FormComponent<?>) applyInfoPanel).setVisible(false);
                wi_btnCancel.setVisible(false);
                wi_btnApply.setVisible(false);
                wi_btnAccept.setVisible(false);
                target.addComponent(form);
            }

        };
        form.add(incApporved);
        form.add(new Label("wi_lbIncApporved", getString("label.incApproved")){
            private static final long serialVersionUID = -1875810882936510916L;

            @Override
            protected void onComponentTag(ComponentTag tag) {
                super.onComponentTag(tag);
                tag.put("for", incApporved.getMarkupId());
            }
        });
    }

    public Object getDefault(PageParameters pars) {
        return approvers;
    }

    public String getEmptyMessage(PageParameters pars) {
        return getString("rejection.reason.empty");
    }

    public void setResult(PageParameters pars) {

    }

}
